package com.taobao.diamond.io.watch;

import com.taobao.diamond.io.Path;
import java.util.Iterator;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public final class WatchService
{
    private BlockingQueue<WatchKey> changedKeys = new LinkedBlockingQueue();

    private BlockingQueue<WatchKey> watchedKeys = new LinkedBlockingQueue();

    private static final Log log = LogFactory.getLog(WatchService.class);
    private ScheduledExecutorService service;

    public WatchService(long checkInterval)
    {
        this.service = Executors.newSingleThreadScheduledExecutor();
        this.service.scheduleAtFixedRate(new CheckThread(), checkInterval, checkInterval, TimeUnit.MILLISECONDS);
    }

    public void check()
    {
        synchronized (this) {
            Iterator it = this.watchedKeys.iterator();
            while (it.hasNext()) {
                WatchKey key = (WatchKey)it.next();
                try {
                    if (key.check()) {
                        this.changedKeys.add(key);
                        it.remove();
                    }
                }
                catch (Throwable t) {
                    log.error("检测WatchKey异常,key=" + key, t);
                }
            }
        }
    }

    public WatchKey register(Path root, WatchEvent.Kind<?>[] events)
    {
        if ((events == null) || (events.length == 0))
            throw new UnsupportedOperationException("null events");
        if (this.service.isShutdown())
            throw new IllegalStateException("服务已经关闭");
        if (!root.exists())
            throw new IllegalArgumentException("监视的目录不存在");
        WatchKey key = new WatchKey(root, this, false, events);
        resetKey(key);
        return key;
    }

    public WatchKey register(Path root, boolean fireCreatedEventOnIndex, WatchEvent.Kind<?>[] events)
    {
        if ((events == null) || (events.length == 0))
            throw new UnsupportedOperationException("null events");
        if (this.service.isShutdown())
            throw new IllegalStateException("服务已经关闭");
        if (!root.exists())
            throw new IllegalArgumentException("监视的目录不存在");
        WatchKey key = new WatchKey(root, this, fireCreatedEventOnIndex, events);
        resetKey(key);
        return key;
    }

    boolean resetKey(WatchKey key)
    {
        return this.watchedKeys.add(key);
    }

    public void close()
    {
        this.service.shutdown();
    }

    public WatchKey poll()
    {
        return (WatchKey)this.changedKeys.poll();
    }

    public WatchKey poll(long timeout, TimeUnit unit)
            throws InterruptedException
    {
        return (WatchKey)this.changedKeys.poll(timeout, unit);
    }

    public WatchKey take()
            throws InterruptedException
    {
        return (WatchKey)this.changedKeys.take();
    }

    private final class CheckThread implements Runnable
    {
        private CheckThread()
        {
        }

        public void run()
        {
            WatchService.this.check();
        }
    }
}